package zct.proj.customView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map.Entry;

import org.metalev.multitouch.controller.MultiTouchController;
import org.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
import org.metalev.multitouch.controller.MultiTouchController.PointInfo;
import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale;

import zct.proj.R;
import zct.proj.pojo.EquipDC;
import zct.proj.pojo.EquipXHJ;
import zct.proj.pojo.EquipmentInfo;
import zct.proj.pojo.LogicSwitcher;
import zct.proj.pojo.StationInfo;
import zct.proj.pojo.StationSummary;
import zct.proj.pojo.Switcher;
import zct.proj.util.ClientThread;
import zct.proj.util.CommUtil;
import zct.proj.util.Const;
import zct.proj.util.DrawBitmapThread;
import zct.proj.util.DrawUtil;
import zct.proj.util.IniParser;
import zct.proj.util.ListItemInterface;
import zct.proj.util.PlaySound;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

public class StationDisplay extends SurfaceView implements SurfaceHolder.Callback, MultiTouchObjectCanvas<StationDisplay.Img> {

	public SurfaceHolder sh;
	Context ctx;
//	Bitmap cacheImage;
	StationSummary ss;
	ArrayList<EquipmentInfo> sbList;
	public StationInfo stationInfo;
	public DrawUtil drawUtil;
	String stationName;
	long eventTime;
	int x, y;
	int lastX, lastY;
	private Timer timer;
	private int reconCount;
	private boolean firstShow2 = true;
	private boolean cancelCon = false;
//	EquipmentInfo rectSb;
	/**
	 * 定位报警开关量与控件的映射关系
	 */
	public HashMap<String, String> warningSwCtlList = new HashMap<String, String>();
//	public ArrayList<Integer> warningCtlList = new ArrayList<Integer>();
//	public ArrayList<HashMap<Integer, String>> warningList = new ArrayList<HashMap<Integer,String>>();
	/**
	 * 当前选中控件的开关量列表
	 */
	public ArrayList<HashMap<String, String>> currentSw = new ArrayList<HashMap<String,String>>();
	/**
	 * 定位报警中开关量对应的报警设置（高、低电平）
	 */
	public HashMap<String, Integer> swStatusMap = new HashMap<String,Integer>();
	/**
	 * 定位报警中的开关量
	 */
	public ArrayList<String> addedSw = new ArrayList<String>();
	//public int warningSelIdx;
	public String warningSelIdx = null;
	
	private PlaySound ps;
	
	boolean drawsth = false;
	boolean screenLock = false;
	boolean connected = false;
	boolean drawing = false;
	boolean firstShow = true;
	private ProgressDialog mpDialog;
	private boolean canDraw = true;
	
	public void stopDrawing() {
		try {
			if (drawThread != null) {
				drawThread.end();
				drawThread = null;
				Log.v("sd", "drawThread destroied!!!!!!!!!!!!!!!!!!!!!!!!");
			}
			canDraw = false;
		} catch (Exception e){};
	}
	
	private void stopThreadDrawing() {
		if (drawThread != null) {
			drawThread.stopDrawing();
		}
	}
	
	public void startDrawing() {
		canDraw = true;
		if (drawThread == null) {
			drawStationMap();
		} else {
			drawThread.startDrawing();
		}
	}
	
	public void addSelectedEquipToList(String swName) {
//		HashMap<Integer, String> item = new HashMap<Integer, String>();
//		item.put(warningSelIdx, "");
//		warningCtlList.add(warningSelIdx);
		warningSwCtlList.put(swName, warningSelIdx);
		addedSw.add(swName);
		int status = getSwitcherStatus(swName, stationInfo);
		swStatusMap.put(swName, status);
		drawStationMap();
	}
	
	public void removeItemFromList(String swName) {
//		Integer idx = warningSwCtlList.get(swName);
//		warningCtlList.remove(idx);
		warningSwCtlList.remove(swName);
		addedSw.remove(swName);
		swStatusMap.remove(swName);
		drawStationMap();
	}
	
	public void setScreenLock(boolean value) {
		screenLock = value;
	}
	public boolean getScreenLock() {
		return screenLock;
	}
//	long eventTime;
//	int x = 0, y = 0;
	
	ClientThread clientThread;
	Thread socketThread;
	public void endAllTask() {
		if (clientThread != null) {
			clientThread.endAllTask();
			clientThread = null;
			socketThread.interrupt();
			socketThread = null;
		}
		
		if (ps != null) {
			ps.end();
			ps = null;
		}
		
		stopDrawing();
	}
    
	Handler handler;
	
	public Img mainImage;
	// --
	private MultiTouchController<Img> multiTouchController = new MultiTouchController<Img>(this);

	// --
	private PointInfo currTouchPoint = new PointInfo();

	private boolean mShowDebugInfo = false;

	private static final int UI_MODE_ROTATE = 1, UI_MODE_ANISOTROPIC_SCALE = 2;

	private int mUIMode = UI_MODE_ROTATE;

	// --
	private Paint mLinePaintTouchPointCircle = new Paint();

	// ---------------------------------------------------------------------------------------------------

//	private void redraw() {
//		if (drawThread != null) {
//			drawThread.setNeedRedraw();
//		}
//	}
	
	private void redraw() {
		
		if (drawing) {
			Log.v("StationDisplay", "Already in drawing, abort.");
			return;
		}
		Canvas canvas = sh.lockCanvas();
		if (canvas != null) {
			drawing = true;
			canvas.drawColor(Color.BLACK);
			
			mainImage.draw(canvas);

			if (mShowDebugInfo) {
				drawMultitouchDebugMarks(canvas);
			}
		}
		sh.unlockCanvasAndPost(canvas);
		drawing = false;
	}

	// ---------------------------------------------------------------------------------------------------

	public void trackballClicked() {
//		mUIMode = (mUIMode + 1) % 3;
//		redraw();
	}

	private void drawMultitouchDebugMarks(Canvas canvas) {
		if (currTouchPoint.isDown()) {
			float[] xs = currTouchPoint.getXs();
			float[] ys = currTouchPoint.getYs();
			float[] pressures = currTouchPoint.getPressures();
			int numPoints = Math.min(currTouchPoint.getNumTouchPoints(), 2);
			for (int i = 0; i < numPoints; i++)
				canvas.drawCircle(xs[i], ys[i], 50 + pressures[i] * 80, mLinePaintTouchPointCircle);
			if (numPoints == 2)
				canvas.drawLine(xs[0], ys[0], xs[1], ys[1], mLinePaintTouchPointCircle);
		}
	}

	// ---------------------------------------------------------------------------------------------------

	private boolean singleTouch = true;
	/** Pass touch events to the MT controller */
	@Override
	public boolean onTouchEvent(MotionEvent event) {

		if (screenLock) {
			return false;
		}
//		long t1=0,t2=0,t3=0,t4=0,t5=0;
//		 t1 = new Date().getTime();
//		Log.i("stadis", mainImage.getScaleX() + "................");
		if (event.getPointerCount() > 1) {
			stopThreadDrawing();
			singleTouch = false;
			return multiTouchController.onTouchEvent(event);
		}
//		 t2 = new Date().getTime();
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
//    		if (event.getPointerCount() >= 2) {
//    			return true;
//    		}
        	
        	stopThreadDrawing();
	    	x = (int) event.getRawX();
	    	y = (int) event.getRawY();
	    	lastX = x;
	    	lastY = y;
	    	eventTime = new Date().getTime();
	    	break;
        case MotionEvent.ACTION_MOVE:
        	if (singleTouch) {
	        	int xDis = (int) event.getRawX() - lastX;
	        	int yDis = (int) event.getRawY() - lastY;
	        	lastX = (int) event.getRawX();
	        	lastY = (int) event.getRawY();
	        	mainImage.setPos(mainImage.getCenterX() + xDis,
	        			mainImage.getCenterY() + yDis,
	        			mainImage.getScaleX(),
	        			mainImage.getScaleY(),
	        			0f);
	        	redraw();
//	        	drawThread.setNeedRedraw();
        	}
//        	this.layout(this.getLeft() + xDis, this.getTop() + yDis, this.getRight() + xDis, this.getBottom() + yDis);
        	break;
        case MotionEvent.ACTION_UP:
        	singleTouch = true;
        	startDrawing();
        	int x2 = (int) event.getRawX();
        	int y2 = (int) event.getRawY();
//        	if (x != x2 || y != y2) {
//        		return true;
//        	}
//        	Log.i("touch event", "action_up. x:"+x2+",y:"+y2);
        	long nowTime = new Date().getTime();
//        	Log.v("action up", x+","+x2+","+y+","+y2+","+eventTime+","+nowTime);
        	if (Math.abs(x2 - x) <= 10 && Math.abs(y2 - y) <= 10 && nowTime - eventTime <= 1000) {
        		// 添加报警处理
    			Rect r = mainImage.getDrawable().getBounds();
    			FrameLayout mapBg = (FrameLayout) this.getParent();
    			int oriX = (int) ((float) (x2 - r.left - mapBg.getLeft()) / r.width() * drawUtil.mapWidth);
    			int oriY = (int) ((float) (y2 - r.top) / r.height() * drawUtil.mapHeight);
    			Log.i("StationDisplay", "orix:"+oriX+",oriy:"+oriY+",r.w:"+r.width()+",r.h:"+r.height()+",r.l:"+r.left+",r.t:"+r.top+",du.mw:"+drawUtil.mapWidth);
//    			r.offsetTo(0, 0);
//    			if (r.contains(oriX, oriY)) {
	    		boolean foundEp = false;
	    		ArrayList<HashMap<String, String>> selList = new ArrayList<HashMap<String,String>>();
	    		String selIdx = "";
        		for (Integer idx : stationInfo.wcqdIdxList) {
        			EquipmentInfo ei = stationInfo.ctlList.get(idx);

        			if (drawUtil.touchedInControll(ei, oriX, oriY)) {
        				// 记录点击处的控件索引
        				selIdx += idx + ",";
//        				currentSw.clear();
        				if (ei.getSwMap() != null) {
	        				// 开关量加入列表
							Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
							while (itsw.hasNext()) {
								Entry<String, Integer> entry = itsw.next();
								String keyTmp = entry.getKey();
								HashMap<String, String> item = new HashMap<String, String>();
								item.put("title", keyTmp);
								if (addedSw.contains(keyTmp)) {
									item.put("button", "取消");
								}
								selList.add(item);
							}
        				}

        				foundEp = true;
            			//Log.i("sd", "found ep #########################################");
//	        				break;
        			}
        		}
        		if (!"".equals(selIdx)) {
        			warningSelIdx = selIdx.substring(0, selIdx.length() - 1);
        		}
	        	if (foundEp) {
	        		// 重绘
	        		drawStationMap();
	        		currentSw = selList;
    				// 调整layout
        			setListLayout(true);
					ListItemInterface act = (ListItemInterface) ctx;
					act.reloadDataSource();
	        	}
//	        	}
        	}
//        	else {
//        		Log.i("sd", "clicked but changed:x:"+Math.abs(x2 - x)+",y:"+Math.abs(y2 - y));
//        	}
        	
        	break;
        }
//		 t5 = new Date().getTime();
		
//		Log.i("StationDisplay", "ontouch time spend:" + (t2-t1));
		return true;
	}
	
	@Override
	public void onLayout(boolean changed, int left, int top, int right, int bottom) {
		if (firstShow) {
			setListLayout(false);
		}
	}
	
	public void setListLayout(boolean isShow) {
		if (isShow) {
			firstShow = false;
		}
		FrameLayout mapBg = (FrameLayout) this.getParent();
		LinearLayout mainBg = (LinearLayout) this.getParent().getParent();
		LinearLayout listLayout = (LinearLayout) mainBg.findViewById(R.id.warnListLayout);
		int w = 0;
		if (isShow) {
			w = 200;
		}
//		listLayout.get
//		listLayout.getMeasuredWidth()
		if (w == listLayout.getWidth()) {
			return;
		} else if (w > 0 && listLayout.getWidth() > 0) {
			return;
		}
		listLayout.layout(0, 0, w, listLayout.getBottom());
		mapBg.layout(w, 0, mapBg.getRight(), mapBg.getBottom());
		this.layout(0, 0, mapBg.getRight(), mapBg.getBottom());
		if (!isShow) {
			warningSelIdx = null;
		}
		
		if (!firstShow && !isShow) {
			redraw();
		}
	}
	
//	private void drawMapWithRect() {
//		Bitmap bmp = mainImage.getDrawable().getBitmap();
//		Canvas canvas = new Canvas(bmp);
//		drawUtil.drawSbWCQDRect(rectSb, canvas);
//		mainImage.changeImage(bmp);
//		redraw();
//	}
	
	/** Get the image that is under the single-touch point, or return null (canceling the drag op) if none */
	public Img getDraggableObjectAtPoint(PointInfo pt) {
		return mainImage;
	}

	private boolean scaling = false;
	/**
	 * Select an object for dragging. Called whenever an object is found to be under the point (non-null is returned by getDraggableObjectAtPoint())
	 * and a drag operation is starting. Called with null when drag op ends.
	 */
	public void selectObject(Img img, PointInfo touchPoint) {
		currTouchPoint.set(touchPoint);

		if (scaling) {
			return;
		}
		scaling = true;
		if (img == null) {
			// 手指离开，重新绘制整张图
			try {
				drawUtil.setScaleAndDraw(mainImage.getScaleX(), stationInfo.getCtlList());
				if (connected) {
					applyChanged(new int[]{});
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
//			Bitmap bm = drawUtil.getCacheBitmap();
//			mainImage.setImage(bm);
			
//			Log.v("sd selectObject", bm.getWidth() + "," + bm.getHeight());
//		} else {
//			Log.v("selectObject", "finger down");
		}
		scaling = false;
//		redraw();
	}

	/** Get the current position and scale of the selected image. Called whenever a drag starts or is reset. */
	public void getPositionAndScale(Img img, PositionAndScale objPosAndScaleOut) {
		// FIXME affine-izem (and fix the fact that the anisotropic_scale part requires averaging the two scale factors)
		objPosAndScaleOut.set(img.getCenterX(), img.getCenterY(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) == 0,
				(img.getScaleX() + img.getScaleY()) / 2, (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0, img.getScaleX(), img.getScaleY(),
				(mUIMode & UI_MODE_ROTATE) != 0, img.getAngle());
//		Log.v("positionAndScale", "called  --------------------------");
	}

	/** Set the position and scale of the dragged/stretched image. */
	public boolean setPositionAndScale(Img img, PositionAndScale newImgPosAndScale, PointInfo touchPoint) {
		currTouchPoint.set(touchPoint);
		boolean ok = img.setPos(newImgPosAndScale);
		if (ok)
			redraw();
//		Log.v("xxxxxx", "happened");
		return ok;
	}
	
	// ----------------------------------------------------------------------------------------------
	
	public StationDisplay(Context context, String stationName) {
		super(context);
		this.stationName = stationName;
		this.setPadding(0, 0, 0, 0);

//		Display disp = ((Activity)context).getWindowManager().getDefaultDisplay();
//		tw = disp.getWidth();
//		th = disp.getHeight();
		ctx = context;
		sh = this.getHolder();
		sh.addCallback(this);
		
    	Resources res = context.getResources();
		mainImage = new Img(res);

		stationInfo = IniParser.getStationInfo(stationName);
		stationInfo.jkxxMap = IniParser.getJKXXList();
		ss = stationInfo.getStationSummary();
		Display disp = ((Activity) ctx).getWindowManager().getDefaultDisplay();
		int tw = disp.getWidth();
		int mapWidth = ss.getScreenWidth();
		float zoomScale = (float) ((int) ((float) tw / mapWidth * 10 )) / 10;
    	drawUtil = new DrawUtil(ctx, ss, zoomScale);
    	// 获得所有控件信息
    	sbList = stationInfo.getCtlList();
    	// 绘制各个控件
    	//drawUtil.drawNet();
    	drawUtil.drawControls(stationInfo.getCtlList());
    	Bitmap cacheImage = drawUtil.getCacheBitmap();
//    	Resources res = ctx.getResources();
    	mainImage.loadBitmap(res, cacheImage);
    	
		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				if (socketThread == null) {
					return;
				}
				if (msg.what == Const.MSG_PLAY_SOUND) {
					// 来自socket的通知
					String sList = msg.getData().getString(Const.MSG_HND);
					if (addedSw.size() > 0) {
						// 定位预警，仅播放OK和FH
						if (sList.startsWith("OK") || sList.startsWith("FH")) {
							// 添加播放列表
							ps.addTask(sList);
						}
					} else {
						// 添加播放列表
						ps.addTask(sList);
					}
				} else if (msg.what == Const.MSG_SWITHCER_CHANGED) {
					int[] list = msg.getData().getIntArray(Const.MSG_HND);
					applyChanged(list);
					drawsth = true;
				} else if (msg.what == Const.MSG_STATION_DATA) {
					setStationInitData(msg.getData().getIntArray(Const.MSG_HND));
					applyChanged(new int[]{});
					connected = true;
					hideWait();
					if (reconCount > 0) {
						ps.addTask("GZ");
						reconCount = 0;
					}
				} else if (msg.what == Const.MSG_ERROR) {
					// 网络中断报警
					if (reconCount == 0 && connected) {
						ps.addTask("TT");
					}
					connected = false;
					if (cancelCon) {
						return;
					}
					
					if (reconCount >= 3) {
						showRetryConfirm();
					} else {
						showWait();
						timer = new Timer();
						TimerTask task = new TimerTask() {
							@Override
							public void run() {
								if (cancelCon) {
									return;
								}
								if (clientThread == null || !clientThread.run) {
									// 重新连接
									reconCount++;
									createSocket();
								}
							}
						};
						timer.schedule(task, 10000);
					}
				}
			}
		};
		showWait();
		createSocket();
		createMP();
	}
	
	private void showRetryConfirm() {
		timer.cancel();
		AlertDialog.Builder builder = new AlertDialog.Builder(ctx);  
		builder.setMessage("连接服务器失败，是否继续重试？");  
		  
		builder.setTitle("提示");  
		builder.setPositiveButton("是", new android.content.DialogInterface.OnClickListener() {
			@Override
			public void onClick(android.content.DialogInterface dialog, int which) {
			    dialog.dismiss();
			    reconCount = 0;
			    showWait();
			    createSocket();
			}
		});
		  
		builder.setNegativeButton("否", new android.content.DialogInterface.OnClickListener() {  
			@Override  
			public void onClick(android.content.DialogInterface dialog, int which) {  
				dialog.dismiss();  
				cancelCon = true;
			}  
		});  
		  
		builder.create().show();
	}
	
	public void surfaceCreated(SurfaceHolder holder) {
    	
    	if (firstShow2) {
    		applyChanged(new int[]{});
    		firstShow2 = false;
    	} else {
    		drawStationMap();
    	}
//		Log.v("sd", "addsw:" + addedSw.size() + ",warnlist:" + warningSwCtlList.size() + ",swstatus:" + swStatusMap.size());
	}
	
	private void showWait() {
		if (mpDialog != null) {
			return;
		}
		mpDialog = new ProgressDialog(ctx);   
        mpDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//设置风格为圆形进度条   
        mpDialog.setTitle("提示");//设置标题   
//        mpDialog.setIcon(android.R.drawable.progress_indeterminate_horizontal);//设置图标   
        mpDialog.setMessage("正在连接服务器");   
        mpDialog.setIndeterminate(true);//设置进度条是否为不明确   
        mpDialog.setCancelable(false);//设置进度条是否可以按退回键取消   
        mpDialog.setButton("取消", new DialogInterface.OnClickListener(){   

            @Override  
            public void onClick(DialogInterface dialog, int which) {
            	try {
	                dialog.cancel();   
	                dialog.dismiss();
            	} catch (Exception e){}
                cancelCon = true;
                clientThread.endAllTask();
                socketThread = null;
                clientThread = null;
                if (ps != null) {
	                ps.end();
	                ps = null;
                }
                stopDrawing();
//                drawThread.end();
//                drawThread = null;
            }   
        });
        try {
        	mpDialog.show();
        } catch(Exception e) {
        	e.printStackTrace();
        }
	}
	
	private void hideWait() {
		if (mpDialog != null) {
			mpDialog.cancel();
			mpDialog.hide();
			mpDialog.dismiss();
			mpDialog = null;
		}
	}
	
	private Thread checkThreadExists(String threadName) {
		ThreadGroup group = Thread.currentThread().getThreadGroup();     
		ThreadGroup parent = null;     
		while ( (parent = group.getParent()) != null ) {     
			group = parent;     
		}     
		Thread[] threads = new Thread[group.activeCount()];     
		group.enumerate(threads);     
		for (int i=0; i < threads.length; ++i) {     
			if (threads[i] != null && threads[i].isAlive()) {
				if (threads[i].getName().equals(threadName)) {
					return threads[i];
				}
			}     
		}
		return null;
	}
	
	private void createDrawThread() {
		if (drawThread == null) {
			Thread t = checkThreadExists("drawmap");
			if (t != null) {
				t.interrupt();
			}
			
			drawThread = new DrawBitmapThread(this);
			Thread thread = new Thread(drawThread);
			thread.setName("drawmap");
			thread.start();
		}
	}
	
	private void createMP() {
//		if (checkThreadExists("mplayer")) {
//			CommUtil.writeLog("mplayer线程已存在，需要关闭。");
//			return;
//		}
		ps = new PlaySound();
		Thread soundThread = new Thread(ps);
		soundThread.setName("mplayer");
		soundThread.start();
	}
	
	private void createSocket() {
		
		if (clientThread != null) {
			if (clientThread.run) {
				return;
			} else {
				clientThread.endAllTask();
				socketThread = null;
				clientThread = null;
			}
		}
		if (checkThreadExists("socket") != null) {
			CommUtil.writeLog("socket线程已存在，无法再次启动。");
			return;
		}
		
		if (cancelCon) {
			return;
		}
		
		try {
//			String mac = CommUtil.getMacAddr(ctx);
//			clientThread = new ClientThread(handler, stationName, mac);
			String mobile = CommUtil.getSetting(ctx, "tel");
			clientThread = new ClientThread(handler, stationName, mobile);
			socketThread = new Thread(clientThread);
			socketThread.setName("socket");
			socketThread.start();
			Log.v("sd", "socket thread created.*************************");
		} catch (IOException e) {
			e.printStackTrace();
			hideWait();
		}
	}

	public void applyChanged(int[] changeArray) {
		
//		if (changeArray.length == 0) {
//			Log.v("sd", "init data applychanged ######################");
//		}
		
//		if (swStatusMap.size() == 0 && !canDrawMap) {
//			return;
//		}
		
		Switcher sw = null;
		Switcher st = null;
//		int cnt = 0;
		// 第一次循环，将所有低电平开关状态清零
		for (int x : changeArray) {
			String key = stationInfo.jkxxMap.get(Math.abs(x));
			if (key == null) {
				continue;
			}
			
			sw = stationInfo.switcherMap.get(key);
			if (sw == null) {
				continue;
			}
			
//			for (Integer swIdx : sw.ctlIdxList) {
			
			if (x < 0) {
				sw.status = 0;
				// 红灯低时设置道岔与无岔区段为无色(忽略白色)
				for (Integer idx : sw.ctlIdxList) {
					EquipmentInfo ei = stationInfo.ctlList.get(idx);
					if (ei.getSwMap() == null || ei.getSwMap().get(key) == null) {
						Log.v("data error", "sb index:"+idx+",sb type:"+ei.getName());
						continue;
					}
					
					if (ei.getName().equals(Const.EQUI_DC)) {
						int swValue = ei.getSwMap().get(key);
						if (swValue == Const.SW_DC_CINDEX_AF_FIX_RED
								|| swValue == Const.SW_DC_CINDEX_AF_OPP_RED
								|| swValue == Const.SW_DC_CINDEX_BEF_RED) {
							Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
							while (itsw.hasNext()) {
								Entry<String, Integer> entry = itsw.next();
								if (entry.getValue() != Const.SW_DC_CINDEX_FIX
										|| entry.getValue() != Const.SW_DC_CINDEX_OPP) {
									String keyTmp = entry.getKey();
									st = stationInfo.switcherMap.get(keyTmp);
									st.status = 0;
								}
							}
						}
					} else if (ei.getName().equals(Const.EQUI_WCQD)) {
						int swValue = ei.getSwMap().get(key);
						if (swValue == Const.SW_WCQD_CINDEX_RED) {
							Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
							while (itsw.hasNext()) {
								Entry<String, Integer> entry = itsw.next();
								String keyTmp = entry.getKey();
								st = stationInfo.switcherMap.get(keyTmp);
								st.status = 0;
							}
						}
					}
				}
			} else {
//				if (sw.type.equals(Const.EQUI_XHJ)) {
//					Log.v("draw lamp", "high at : " + key + ", color index:" + sw.colorIndex);
//				}
				boolean changeSwValue = true;
				for (Integer idx : sw.ctlIdxList) {
					EquipmentInfo ei = stationInfo.ctlList.get(idx);
					if (ei.getSwMap() == null || ei.getSwMap().get(key) == null) {
						Log.v("data error", "sb index:"+idx+",sb type:"+ei.getName());
					}
					int swIdx = 0;
					if (ei.getSwMap().keySet().contains(key)) {
						swIdx = ei.getSwMap().get(key);
					} else {
						if (((EquipDC) ei).getSwPosList().get(0).equals(key)) {
							swIdx = Const.SW_DC_CINDEX_FIX;
						} else {
							swIdx = Const.SW_DC_CINDEX_OPP;
						}
					}
					if (ei.getName().equals(Const.EQUI_DC) 
							&& (swIdx == Const.SW_DC_CINDEX_FIX 
							|| swIdx == Const.SW_DC_CINDEX_OPP)) {
						EquipDC edc = (EquipDC) ei;
						// 道岔定位与反位开关量重置
						if (swIdx == Const.SW_DC_CINDEX_FIX) {
							// 定位高
							edc.setStatus(0);
						} else {
							edc.setStatus(1);
						}
						ArrayList<String> swPosList = edc.getSwPosList();
						if (swPosList != null) {
							for (String s : swPosList) {
								st = stationInfo.switcherMap.get(s);
								st.status = 0;
							}
						}
					} else if (ei.getName().equals(Const.EQUI_XHJ) 
							&& swIdx == Const.SW_XHJ_CINDEX_YELLOW
							&& ((EquipXHJ) ei).lampCount == 2) {
						Log.v("stationDisp", "apply change with DC for name:"+ei.getDisp());
						// 信号机黄灯亮时灭绿灯外的另一个灯位
						Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
						while (itsw.hasNext()) {
							Entry<String, Integer> entry = itsw.next();
							String keyTmp = entry.getKey();
							st = stationInfo.switcherMap.get(keyTmp);
							if (entry.getValue() != Const.SW_XHJ_CINDEX_GREEN) {
								st.status = 0;
							}
						}
					} else if (ei.getName().equals(Const.EQUI_WCQD)) {
						// 开关对应控件的所有开关量状态清零
						Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
						while (itsw.hasNext()) {
							Entry<String, Integer> entry = itsw.next();
							String keyTmp = entry.getKey();
							st = stationInfo.switcherMap.get(keyTmp);
							if (entry.getValue() == Const.SW_WCQD_CINDEX_RED && st.status == 1) {
								changeSwValue = false;
							} else {
								st.status = 0;
							}
						}
					} else {
						// 开关对应控件的所有开关量状态清零
						Iterator<Entry<String, Integer>> itsw = ei.getSwMap().entrySet().iterator();
						while (itsw.hasNext()) {
							Entry<String, Integer> entry = itsw.next();
							String keyTmp = entry.getKey();
							st = stationInfo.switcherMap.get(keyTmp);
							if (entry.getValue() != Const.SW_XHJ_CINDEX_GREEN) {
								st.status = 0;
							}
						}
					}
				}
				if (changeSwValue) {
					sw.status = 1;
				}
			}
		}
		// 重新计算所有逻辑开关量的值
		Iterator<Entry<String, LogicSwitcher>> lsLoop = stationInfo.lsMap.entrySet().iterator();
		while (lsLoop.hasNext()) {
			Entry<String, LogicSwitcher> entry = lsLoop.next();
			LogicSwitcher ls = entry.getValue();

			int ret = getSwitcherStatus(entry.getKey(), stationInfo);
			ls.status = ret;
			Switcher tmpSw = stationInfo.switcherMap.get(entry.getKey());
			if (tmpSw != null) {
				tmpSw.status = ret;
			}
		}
		// 标记预警开关量的状态，用于判断是否播音
		Iterator<Entry<String, Integer>> it = swStatusMap.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, Integer> entry = it.next();
			String key = entry.getKey();
			Integer value = getSwitcherStatus(key, stationInfo);
			if (value != entry.getValue()) {
				swStatusMap.put(key, value);
				if (value == 1) {
					// 高电平，播音
					if (key.endsWith("B")) {
						// 白,KF（信号开放）
						ps.addTask("KF,");
						ps.addTask("KF,");
					} else if (key.endsWith("H")) {
						// 红,LJ（列车接近）
						ps.addTask("LJ,");
						ps.addTask("LJ,");
					}
					Log.i("StationDisplay", "sw value changed:"+key);
				}
			}
		}
		
		// 遍历开关列表，将所有高电平开关画到图上
		drawStationMap();
//		Log.i("StationDisplay", "time spend:"+(t2-t1)+","+(t3-t2)+","+(t4-t3));
	}
	
	private DrawBitmapThread drawThread;
	public void drawStationMap() {
		if (!canDraw) {
			return;
		}
		createDrawThread();
		drawThread.setNeedRedraw();
		return;
		
	}
	
	private int getSwitcherStatus(String swName, StationInfo si) {
		
//		Switcher sw = si.switcherMap.get(swName);
//		if (sw != null) {
//			return sw.status;
//		} else {
		LogicSwitcher ls = si.lsMap.get(swName);
		if (ls == null) {
			// 非逻辑开关量，直接从开关map中取值
			return si.switcherMap.get(swName).status;
		} else {
			// 逻辑开关量，要计算
			int v = 0;
			if (ls.swNames[0].equals(swName)) {
				// 逻辑开关量与计算用的开关量同名时，为避免死循环，应从switcherMap中取值
				v = stationInfo.switcherMap.get(swName).status;
			} else {
				v = getSwitcherStatus(ls.swNames[0], si);
			}
			
			// 是否取反
			if (ls.useReserve[0]) {
				v = ~v;
			}
			
			int ret = v;
			for (int i = 1; i < ls.swCount; i ++) {
				int v1 = 0;
				if (ls.swNames[i].equals(swName)) {
					// 逻辑开关量与计算用的开关量同名时，为避免死循环，应从switcherMap中取值
					v1 = stationInfo.switcherMap.get(swName).status;
				} else {
					v1 = getSwitcherStatus(ls.swNames[i], si);
				}
				// 是否取反
				if (ls.useReserve[i]) {
					v1 = ~v1;
				}
				ret = LogicSwitcher.getSwValue(v, v1, ls.method);
				v = ret;
			}
			return ret;
		}
	}
	
	public static int getDrawColor(String ctlType, int index) {
		return getDrawColor(ctlType, 0, index);
	}
	
	public static int getDrawColor(String ctlType, int detailType, int index) {
		if (ctlType.equals(Const.EQUI_XHJ)) {
			switch (index) {
			case Const.SW_XHJ_CINDEX_BLUE:
				return Color.BLUE;
			case Const.SW_XHJ_CINDEX_GREEN:
				return Color.GREEN;
			case Const.SW_XHJ_CINDEX_GREEN2:
				return Color.GREEN;
			case Const.SW_XHJ_CINDEX_RED:
				if (detailType == Const.TYPE_XHJ_DCAZ || detailType == Const.TYPE_XHJ_DCGZ) {
					return Color.BLUE;
				} else {
					return Color.RED;
				}
			case Const.SW_XHJ_CINDEX_WHITE:
				return Color.WHITE;
			case Const.SW_XHJ_CINDEX_YELLOW:
				return Color.YELLOW;
			case Const.SW_XHJ_CINDEX_YELLOW2:
				return Color.YELLOW;
			}
		} else if (ctlType.equals(Const.EQUI_DHAN)) {
			switch (index) {
			case Const.SW_DHAN_CINDEX_BLUE:
				return Color.BLUE;
			case Const.SW_DHAN_CINDEX_GREEN:
				return Color.GREEN;
			case Const.SW_DHAN_CINDEX_RED:
				return Color.RED;
			case Const.SW_DHAN_CINDEX_SIG:
				return Color.CYAN;
			case Const.SW_DHAN_CINDEX_WHITE:
				return Color.WHITE;
			case Const.SW_DHAN_CINDEX_YELLOW:
				return Color.YELLOW;
			}
		} else if (ctlType.equals(Const.EQUI_WCQD)) {
			switch (index) {
			case Const.SW_WCQD_CINDEX_RED:
				return Color.RED;
			case Const.SW_WCQD_CINDEX_WHITE:
				return Color.WHITE;
			}
		} else if (ctlType.equals(Const.EQUI_DC)) {
			switch (index) {
			case Const.SW_DC_CINDEX_AF_FIX_RED:
			case Const.SW_DC_CINDEX_AF_OPP_RED:
			case Const.SW_DC_CINDEX_BEF_RED:
				return Color.RED;
			case Const.SW_DC_CINDEX_AF_FIX_WHITE:
			case Const.SW_DC_CINDEX_AF_OPP_WHITE:
			case Const.SW_DC_CINDEX_BEF_WHITE:
				return Color.WHITE;
			case Const.SW_DC_CINDEX_FIX:
			case Const.SW_DC_CINDEX_OPP:
				return Color.GRAY;
			}
		}
		return 0;
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}
	
	public void setStationInitData(int[] data) {
		Log.v("set station", data[0] + "," + data[1] + "," + data[2]);
		int iStart = 0;
		int len = data.length;
		if (data[0] == 0x01 && data[1] == 0x22) {
			iStart = 4;
			len -= 7;
		}
		for (int i = iStart; i < len; i++) {
			int tmp = data[i + iStart];
			for (int j = 0; j < 8; j++) {
//				int key = i * 8 + (8 - j);
//				int value = tmp & 0x1;
//				Log.v("initData", "key:"+key+",value:"+value);
				String key = stationInfo.jkxxMap.get((i - iStart) * 8 + j + 1);
//				int x = (i - iStart) * 8 + j + 1;

				Switcher sw = stationInfo.switcherMap.get(key);
				if (sw != null) {
					sw.status = (tmp >>> j) & 0x1;
				}
			}
		}
		
		for (Integer idx : stationInfo.dcIdxList) {
			// 道岔的定位与反位
			EquipDC dc = (EquipDC) stationInfo.ctlList.get(idx);
			String swName = dc.getSwPosList().get(1);
			Switcher sw = stationInfo.switcherMap.get(swName);
			dc.setStatus(sw.status == 1 ? 1 : 0);
		}
	}
	
	// ----------------------------------------------------------------------------------------------

	public class Img {
//		private int resId;

		private BitmapDrawable drawable;

		private boolean firstLoad;

		private int width, height, displayWidth, displayHeight;

		private float centerX, centerY, scaleX, scaleY, angle;

		private float minX, maxX, minY, maxY;

		private static final float SCREEN_MARGIN = 0;

		public Img(Resources res) {
//			this.resId = resId;
			this.firstLoad = true;
			getMetrics(res);
		}

		private void getMetrics(Resources res) {
			DisplayMetrics metrics = res.getDisplayMetrics();
			// The DisplayMetrics don't seem to always be updated on screen rotate, so we hard code a portrait
			// screen orientation for the non-rotated screen here...
			// this.displayWidth = metrics.widthPixels;
			// this.displayHeight = metrics.heightPixels;
			this.displayWidth = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math.max(metrics.widthPixels,
					metrics.heightPixels) : Math.min(metrics.widthPixels, metrics.heightPixels);
			this.displayHeight = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? Math.min(metrics.widthPixels,
					metrics.heightPixels) : Math.max(metrics.widthPixels, metrics.heightPixels);
		}
		
		public void changeImage(Bitmap img) {
			this.drawable = new BitmapDrawable(img);
		}

		public void loadBitmap(Resources res, Bitmap img) {
			getMetrics(res);
			this.drawable = new BitmapDrawable(img);
			this.width = img.getWidth();// drawable.getIntrinsicWidth();
			this.height = img.getHeight();// drawable.getIntrinsicHeight();
			float cx, cy;
			if (firstLoad) {
				cx = SCREEN_MARGIN + (float) (displayWidth - 2 * SCREEN_MARGIN);
				cy = SCREEN_MARGIN + (float) (displayHeight - 2 * SCREEN_MARGIN);
//				float sc = (float) (Math.max(displayWidth, displayHeight) / (float) Math.max(width, height) * Math.random() * 0.3 + 0.2);
//				sx = sy = sc;
				firstLoad = false;
			} else {
				// Reuse position and scale information if it is available
				// FIXME this doesn't actually work because the whole activity is torn down and re-created on rotate
				cx = this.centerX;
				cy = this.centerY;
//				sx = this.scaleX;
//				sy = this.scaleY;
				// Make sure the image is not off the screen after a screen rotation
				if (this.maxX < SCREEN_MARGIN)
					cx = SCREEN_MARGIN;
				else if (this.minX > displayWidth - SCREEN_MARGIN)
					cx = displayWidth - SCREEN_MARGIN;
				if (this.maxY > SCREEN_MARGIN)
					cy = SCREEN_MARGIN;
				else if (this.minY > displayHeight - SCREEN_MARGIN)
					cy = displayHeight - SCREEN_MARGIN;
			}
			setPos(cx / 2, cy / 2, 1, 1, 0.0f);
		}
		
		
//		/** Called by activity's onResume() method to load the images */
//		public void load(Resources res) {
//			getMetrics(res);
//			this.drawable = res.getDrawable(resId);
//			this.width = drawable.getIntrinsicWidth();
//			this.height = drawable.getIntrinsicHeight();
//			float cx, cy, sx, sy;
//			if (firstLoad) {
//				cx = SCREEN_MARGIN + (float) (Math.random() * (displayWidth - 2 * SCREEN_MARGIN));
//				cy = SCREEN_MARGIN + (float) (Math.random() * (displayHeight - 2 * SCREEN_MARGIN));
//				float sc = (float) (Math.max(displayWidth, displayHeight) / (float) Math.max(width, height) * Math.random() * 0.3 + 0.2);
//				sx = sy = sc;
//				firstLoad = false;
//			} else {
//				// Reuse position and scale information if it is available
//				// FIXME this doesn't actually work because the whole activity is torn down and re-created on rotate
//				cx = this.centerX;
//				cy = this.centerY;
//				sx = this.scaleX;
//				sy = this.scaleY;
//				// Make sure the image is not off the screen after a screen rotation
//				if (this.maxX < SCREEN_MARGIN)
//					cx = SCREEN_MARGIN;
//				else if (this.minX > displayWidth - SCREEN_MARGIN)
//					cx = displayWidth - SCREEN_MARGIN;
//				if (this.maxY > SCREEN_MARGIN)
//					cy = SCREEN_MARGIN;
//				else if (this.minY > displayHeight - SCREEN_MARGIN)
//					cy = displayHeight - SCREEN_MARGIN;
//			}
//			setPos(cx, cy, sx, sy, 0.0f);
//		}

		/** Called by activity's onPause() method to free memory used for loading the images */
		public void unload() {
			this.drawable = null;
		}

		/** Set the position and scale of an image in screen coordinates */
		public boolean setPos(PositionAndScale newImgPosAndScale) {
			return setPos(newImgPosAndScale.getXOff(), newImgPosAndScale.getYOff(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0 ? newImgPosAndScale
					.getScaleX() : newImgPosAndScale.getScale(), (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0 ? newImgPosAndScale.getScaleY()
					: newImgPosAndScale.getScale(), newImgPosAndScale.getAngle());
			// FIXME: anisotropic scaling jumps when axis-snapping
			// FIXME: affine-ize
			// return setPos(newImgPosAndScale.getXOff(), newImgPosAndScale.getYOff(), newImgPosAndScale.getScaleAnisotropicX(),
			// newImgPosAndScale.getScaleAnisotropicY(), 0.0f);
		}

		/** Set the position and scale of an image in screen coordinates */
		public boolean setPos(float centerX, float centerY, float scaleX, float scaleY, float angle) {
			float ws = (width / 2) * scaleX, hs = (height / 2) * scaleY;
			float newMinX = centerX - ws, newMinY = centerY - hs, newMaxX = centerX + ws, newMaxY = centerY + hs;
			if (newMinX > displayWidth - SCREEN_MARGIN || newMaxX < SCREEN_MARGIN || newMinY > displayHeight - SCREEN_MARGIN
					|| newMaxY < SCREEN_MARGIN)
				return false;
			
			if (scaleX > 3f || scaleX < 0.7f) {
				return false;
			} else {
				int resolution = ss.getScreenWidth() * ss.getScreenHeight();
				if (scaleX * resolution > Const.MAX_RESOLUTION) {
					return false;
				}
			}
//			Log.i("setPos", "width:"+(this.width * scaleX));
			this.centerX = centerX;
			this.centerY = centerY;
			this.scaleX = scaleX;
			this.scaleY = scaleY;
			this.angle = angle;
			this.minX = newMinX;
			this.minY = newMinY;
			this.maxX = newMaxX;
			this.maxY = newMaxY;
			return true;
		}

		/** Return whether or not the given screen coords are inside this image */
		public boolean containsPoint(float scrnX, float scrnY) {
			// FIXME: need to correctly account for image rotation
			return (scrnX >= minX && scrnX <= maxX && scrnY >= minY && scrnY <= maxY);
		}

		public void draw(Canvas canvas) {
			if (canvas != null) {
//				canvas.save();
	//			float dx = (maxX + minX) / 2;
	//			float dy = (maxY + minY) / 2;
				drawable.setBounds((int) minX, (int) minY, (int) maxX, (int) maxY);
	//			canvas.translate(dx, dy);
	//			canvas.rotate(angle * 180.0f / (float) Math.PI);
	//			canvas.translate(-dx, -dy);
				drawable.draw(canvas);
//				canvas.restore();
			} else {
				Log.v("StationDisplay", "draw error, canvas is null");
			}
		}

		public BitmapDrawable getDrawable() {
			return drawable;
		}
		
//		public void setImage(Bitmap bm) {
//			BitmapDrawable bd = new BitmapDrawable(bm);
//			drawable = bd;
//		}

		public int getWidth() {
			return width;
		}

		public int getHeight() {
			return height;
		}

		public float getCenterX() {
			return centerX;
		}

		public float getCenterY() {
			return centerY;
		}

		public float getScaleX() {
			return scaleX;
		}

		public float getScaleY() {
			return scaleY;
		}

		public float getAngle() {
			return angle;
		}

		// FIXME: these need to be updated for rotation
		public float getMinX() {
			return minX;
		}

		public float getMaxX() {
			return maxX;
		}

		public float getMinY() {
			return minY;
		}

		public float getMaxY() {
			return maxY;
		}
	}
}
